// -----------------------------------------------------------------------
//  <copyright file="GetUserAccessCodesQuery.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2025 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2025-03-09 16:03</last-date>
// -----------------------------------------------------------------------

using DaprPlus.Authorization.Domain.Entities;
using DaprPlus.Identity;
using DaprPlus.Specifications;
using OSharp.Extensions;
using System.Security.Claims;

namespace DaprPlus.Authorization.Application.Queries;

[AuthConfig(typeof(RoleResource), ResourceAccessType.Anonymous, "GetUserAccessCodes")]
public record GetUserAccessCodesQuery : IRequest<string[]>;

public class GetUserAccessCodesQueryHandler(IServiceProvider provider)
    : IRequestHandler<GetUserAccessCodesQuery, string[]>
{
    public async Task<string[]> Handle(GetUserAccessCodesQuery request, CancellationToken cancellationToken)
    {
        var currentUser = provider.GetCurrentUser();
        var authCache = provider.GetRequiredService<IAuthorizationCache>();
        var codes = new List<string>();

        var resourceRepository = provider.GetQueryRepository<Resource>();
        var topRoleService = provider.GetRequiredService<ITopAdminRoleService>();

        // 从缓存中获取所有资源
        var spec = new TrueSpecification<Resource>();
        var resources = await resourceRepository.GetAllAsync(spec, cancellationToken);

        if (currentUser?.Identity?.IsAuthenticated != true)
        {
            // 未登录用户，只获取匿名资源
            foreach (var resource in resources)
            {
                var operations = resource.GetAllowedOperations();
                codes.AddRange(GetAccessCodes(resource, operations.Where(m => m.AccessType == ResourceAccessType.Anonymous).ToArray()));
            }
        }
        else
        {
            // 已登录用户，获取匿名资源、登录可访问资源和角色资源
            var roleNames = currentUser.Identity.GetRoles();
            var resolver = provider.GetRequiredService<IRoleNameResolver>();
            var roleIds = await resolver.ResolveRoleIds(roleNames);

            foreach (var resource in resources)
            {
                var operations = resource.GetAllowedOperations();
                if (operations.Length == 0)
                {
                    continue;
                }
                if (await topRoleService.IsTopAdminRole(roleIds))
                {
                    codes.AddRange(GetAccessCodes(resource, operations.ToArray()));
                    continue;
                }

                // 匿名访问或登录访问的操作码
                codes.AddRange(GetAccessCodes(resource, operations.Where(m => m.AccessType == ResourceAccessType.Anonymous).ToArray()));

                if (roleIds.Length == 0)
                {
                    continue;
                }
                var authItems = await authCache.GetOrBuildResourceAuthorizationCache(resource);
                foreach (var authItem in authItems.Where(m => roleIds.Contains(m.RoleId)))
                {
                    if (authItem.Operations.Length == 0)
                    {
                        continue;
                    }
                    codes.AddRange(GetAccessCodes(resource, operations.Where(opt => authItem.Operations.Contains(opt.Code)).ToArray()));
                }
            }
        }

        return codes.ToArray();
    }

    /// <summary>
    /// 获取资源的权限码列表
    /// </summary>
    /// <param name="resource">资源信息</param>
    /// <param name="operations">操作列表</param>
    /// <returns>权限码列表</returns>
    private static IEnumerable<string> GetAccessCodes(Resource resource, ResourceOperation[] operations)
    {
        // 获取资源类型的简单名称（去掉命名空间）
        var resourceName = resource.Code.Split('.').Last();
        return operations.Select(operation => $"{resourceName}:{operation.Code}");
    }
}

